package view.cms.desktop
{
    import flash.display.DisplayObjectContainer;
    import flash.events.*;
    import flash.geom.*;
    
    import mx.core.*;
    import mx.managers.*;
    
    import view.cms.desktop.events.*;

    public class Manipulator extends Container implements IFocusManagerComponent 
    {
		private var blrh:ResizeHandle;
        private var resizeVanishingPoint:Point;
        private var outlineColor:uint;
        public var miny:Number;
        private var rsmColor:uint;
        public var minx:Number;
        private var drawCornerMarkers:Boolean;
        private var rsmSize:Number;
        private var _relCenter:Point;
        private var rhGap:Number;
        private var trrh:ResizeHandle;
        private var rsmGap:Number;
        public var activeHandle:ResizeHandle;
        private var currentCol:uint;
        private var outlineThickness:Number;
        private var trh:ResizeHandle;
		private var rhThickness:Number;
        private var _absCenter:Point;
        private var resizeStartX:Number;
        private var brh:ResizeHandle;
        private var resizeStartY:Number;
        private var rrh:ResizeHandle;
        private var outlineAlpha:Number;
        private var rhLockedColor:uint;
        private var rsmAlpha:Number;
        private var rhRadius:Number;
        private var brrh:ResizeHandle;
        private var resizeStartWidth:Number;
        private var tlrh:ResizeHandle;
        private var rhColor:uint;
        private var resizeStartHeight:Number;
        private var drawEdgeMarkers:Boolean;
        public var maxy:Number;
        private var lrh:ResizeHandle;
//        public var rotator:RotateHandle;
        public var maxx:Number;
        private var _angle:Number;
        private var resizeResizePoint:Point;

        public function Manipulator(x:Number,y:Number,width:Number,height:Number, ro:Number=0, cornerMarks:Boolean=true)
        {
			rsmSize = 10;
            rsmGap = -5;
            rsmColor = 0x88d2ce;
            rsmAlpha = 0.6;
            drawEdgeMarkers = false;
            drawCornerMarkers = true;
            outlineColor = 0xf57e07;
            outlineThickness = 4;
            outlineAlpha = 0.4;
            rhGap = 20;
            rhRadius = 6;
            rhColor = 0xff0000;
            rhLockedColor = 0xf24d5c;
            rhThickness = 2;
            activeHandle = null;
            _angle = 0;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.verticalScrollPolicy = ScrollPolicy.OFF;
            this.horizontalScrollPolicy = ScrollPolicy.OFF;
            this.clipContent = false;
            this.drawCornerMarkers = cornerMarks;
            relCenter = new Point((this.width / 2), (this.height / 2));
            this.rotate(ro);
            
            if (drawCornerMarkers)
            {
                tlrh = new ResizeHandle();
                this.addChild(tlrh);
                trrh = new ResizeHandle();
                this.addChild(trrh);
                blrh = new ResizeHandle();
                this.addChild(blrh);
                brrh = new ResizeHandle();
                this.addChild(brrh);
            };
            
            if (drawEdgeMarkers)
            {
                trh = new ResizeHandle();
                this.addChild(trh);
                brh = new ResizeHandle();
                this.addChild(brh);
                rrh = new ResizeHandle();
                this.addChild(rrh);
                lrh = new ResizeHandle();
                this.addChild(lrh);
            };
            
            this.addEventListener(MouseEvent.MOUSE_DOWN, this.startMove);
            this.addEventListener(MouseEvent.ROLL_OVER,this.toDrag);
            this.addEventListener(MouseEvent.ROLL_OUT,this.offDrag);
//          this.addEventListener(DragEvent.DRAG_ENTER, this.acceptObject);
        }
        
        
        private function toDrag(evt:MouseEvent):void
        {
            dispatchEvent(new CursorChangeEvent(CursorChangeEvent.CHANGE, true, true, "drag"));
        }
        
        private function offDrag(evt:MouseEvent):void
        {
            dispatchEvent(new CursorChangeEvent(CursorChangeEvent.CHANGE, true, true, null));
        }
        
        public function get TLC():Point
        {
            if (relCenter)
            {
                var len:Number = _relCenter.length;
                var asin:Number = Math.asin(Math.abs(_relCenter.y) / len);
                var a:Number = Math.PI - (this.angle + Math.PI / 2);
                var b:Number = a - asin;
                b = Math.PI * 2 - (b - Math.PI / 2);
                var pt:Point = Point.polar(len, b);
                var ma:Matrix = new Matrix();
                ma.rotate(-this.angle);
                var pt2:Point = ma.deltaTransformPoint(new Point(-pt.x, -pt.y));
                pt2.x = pt2.x + pt.x + this.x;
                pt2.y = pt2.y + pt.y + this.y;
                return pt2;
            };
            
            return null;
        }
        
        override public function set x(x:Number):void
        {
            super.x = x;
            var pt:Point = this.TLC;
            
            if ( pt )
            {
                _absCenter = new Point((pt.x + _relCenter.x), (pt.y + _relCenter.y));
            };
        }
        
        override public function set y(y:Number):void
        {
            super.y = y;
            var pt:Point = this.TLC;
            
            if ( pt )
            {
                _absCenter = new Point((pt.x + _relCenter.x), (pt.y + _relCenter.y));
            };
        }
        
		public function set relCenter(pt:Point):void
        {
			this._relCenter = pt;
			pt = this.TLC;
            
            if ( pt )
            {
                _absCenter = new Point((pt.x + _relCenter.x), (pt.y + _relCenter.y));
            };
        }
        
        public function get angle():Number
        {
			return this._angle;
        }
        
		public function relativeToAbsolute(rel:Point):Point
        {
            var ma:Matrix = new Matrix();
            ma.rotate(this.angle);
			ma.translate(_absCenter.x, _absCenter.y);
            var pt:Point = ma.deltaTransformPoint(new Point((rel.x - relCenter.x), (rel.y - relCenter.y)));
            pt.x = (pt.x + _absCenter.x);
            pt.y = (pt.y + _absCenter.y);
            return pt;
        }
        
        public function rotate(angle:Number):void
        {
        	var ma:Matrix = new Matrix();
            ma.rotate(angle);
            var pt:Point = ma.deltaTransformPoint(this.relCenter);
            ma.translate((_absCenter.x - pt.x), (_absCenter.y - pt.y));
            this.transform.matrix = ma;
            dispatchEvent(new RotateEvent(RotateEvent.ROTATE, true, true, _absCenter, angle));
            this.angle = angle;
        }
        
        override public function setFocus():void
        {
            if (this.parent is DrawingPage)
            {
                DrawingPage(this.parent).setFocus();
            };
        }
        
//        public function startRotation():void
//        {
//        	DrawingPage(this.parent).startRotation(_absCenter.x, _absCenter.y);
//        }
        
        public function moveTo(pt:Point, pt2:Point):void
        {
            this.x = (pt.x + pt2.x);
            this.y = (pt.y + pt2.y);
            dispatchEvent(new ShiftEvent(ShiftEvent.SHIFT, true, true, pt.x, pt.y));
        }

        
		public function get relCenter():Point
		{
			return (_relCenter);
		}
        
        public function findExtents():void
        {
            maxx = 0;
            maxy = 0;
            minx = this.x;
            miny = this.y;
            var points:Array = [new Point(0, 0), new Point(width, 0), new Point(width, height), new Point(0, height)];
            var ma:Matrix = new Matrix();
            ma.rotate(this.angle);
            var i:int = 0;
                
            while (i < points.length) 
            {
                var pt:Point = ma.deltaTransformPoint(points[i]);
                
                if (pt.x + this.x > maxx)
                {
                    maxx = pt.x + this.x;
                };
                
                if (pt.y + this.y > maxy)
                {
                    maxy = pt.y + this.y;
                };
                
                if (pt.x + this.x < minx)
                {
                    minx = pt.x + this.x;
                };
                
                if (pt.y + this.y < miny)
                {
                    miny = pt.y + this.y;
                };
                
                i++;
            };
        }
        
        public function set absCenter(_arg1:Point):void
        {
            this._absCenter = _arg1;
        }
        
        private function updateSelectionMarkers():void
        {
            if ( tlrh && trrh && blrh && brrh )
            {
                tlrh.update(-(rsmSize + rsmGap), -(rsmSize + rsmGap), rsmSize, rsmSize, width, height, 0, 0, true, true, currentCol);
                blrh.update(-(rsmSize + rsmGap), height + rsmGap, rsmSize, rsmSize, width, 0, 0, height, true, true, currentCol);
                brrh.update(width + rsmGap, height + rsmGap, rsmSize, rsmSize, 0, 0, width, height, true, true, currentCol);
                trrh.update(width + rsmGap, -(rsmSize + rsmGap), rsmSize, rsmSize, 0, height, width, 0, true, true, currentCol);
            };
            
            if ( trh && brh && lrh && rrh)
            {
                trh.update(width / 2 - rsmSize / 2, -(rsmSize + rsmGap), rsmSize, rsmSize, width / 2, height, width / 2, 0, false, true, currentCol);
                brh.update(width / 2 - rsmSize / 2, height + rsmGap, rsmSize, rsmSize, width / 2, 0, width / 2, height, false, true, currentCol);
                lrh.update(-(rsmSize + rsmGap), height / 2 - rsmSize / 2, rsmSize, rsmSize, width, height / 2, 0, height / 2, true, false, currentCol);
                rrh.update(width + rsmGap, height / 2 - rsmSize / 2, rsmSize, rsmSize, 0, height / 2, width, height / 2, true, false, currentCol);
            };
        }
        
        private function startMove(evt:MouseEvent):void
        {
            this.setFocus();
            
            evt.stopPropagation();
            
            if (evt.shiftKey)
            {
                DrawingPage(this.parent).selectAndUnselect();
            } 
            else
            {
                if (DrawingPage(this.parent).hitShapeUnderManip())
                {
                    var dp:DrawingPage = DrawingPage(this.parent)
                    dp.selectShapeUnderMouse();                    
                } 
                else 
                {
                    DrawingPage(this.parent).startMove(new Point(this.x, this.y),true);
                };
            };
        }
         
        public function get absCenter():Point
        {
            return (_absCenter);
        }
        
        public function setSize(pt:Point):void
        {
            if ( resizeVanishingPoint && this.resizeResizePoint )
            {
                if (!this.activeHandle.allowScaleX)
                {
                    pt.x = this.width;
                };
                
                if (!this.activeHandle.allowScaleY)
                {
                    pt.y = this.height;
                };
                
                if ( resizeResizePoint.x - resizeVanishingPoint.x >= 0 && pt.x < 0 && this.activeHandle.allowScaleX )
                {
                    return;
                };
                
                if ( resizeResizePoint.y - resizeVanishingPoint.y >= 0 && pt.y < 0 && this.activeHandle.allowScaleY )
                {
                    return;
                };
                
                if ( resizeResizePoint.x - resizeVanishingPoint.x <= 0 && pt.x > 0 && this.activeHandle.allowScaleX )
                {
                    return;
                };
                
                if ( resizeResizePoint.y - resizeVanishingPoint.y <= 0 && pt.y > 0 && this.activeHandle.allowScaleY )
                {
                    return;
                };
                
                if (this.activeHandle.allowScaleX)
                {
                    this.width = Math.abs(pt.x) * this.resizeStartWidth / Math.abs(resizeResizePoint.x - resizeVanishingPoint.x);
                };
                
                if (this.activeHandle.allowScaleY)
                {
                    this.height = Math.abs(pt.y) * this.resizeStartHeight / Math.abs(resizeResizePoint.y - resizeVanishingPoint.y);
                };
                
                this.relCenter = new Point((this.width / 2), (this.height / 2));

				var deltaX:Number = (resizeResizePoint.x - resizeVanishingPoint.x) < 0 
                	? ( pt.x - (resizeResizePoint.x - resizeVanishingPoint.x)) : 0; 
                var deltaY:Number = (resizeResizePoint.y - resizeVanishingPoint.y) < 0 
                	? ( pt.y - (resizeResizePoint.y - resizeVanishingPoint.y)) : 0; 
                
                var ma:Matrix = new Matrix();
                
                ma.rotate(this.angle);
                
                var pt2:Point = ma.deltaTransformPoint(new Point(deltaX,deltaY));
                
                this.x = (resizeStartX + pt2.x);
                
                this.y = (resizeStartY + pt2.y);
                
                dispatchEvent(new ResizeEvent(ResizeEvent.RESIZE_SHAPE, true, true, pt, activeHandle.allowScaleX, activeHandle.allowScaleY));
                
                this.invalidateDisplayList();
            };
        }
  		
  		public function setSizeManually(width:Number,height:Number):void
  		{
			this.width = width;
			this.height = height;
            this.relCenter = new Point((this.width / 2), (this.height / 2));
            this.invalidateDisplayList();
  		}
  		
        public function set angle(angle:Number):void
        {
            _angle = angle;
            invalidateDisplayList();
        }
        
		public function startResize(handle:ResizeHandle):void
         {
			this.activeHandle = handle;
			this.resizeVanishingPoint = handle.vanishingPoint;
			this.resizeResizePoint = handle.resizePoint;
            this.resizeStartWidth = this.width;
            this.resizeStartHeight = this.height;
            this.resizeStartX = this.x;
            this.resizeStartY = this.y;
			DrawingPage(this.parent).startResize(relativeToAbsolute(handle.vanishingPoint), relativeToAbsolute(handle.resizePoint), relativeToAbsolute(new Point(this.mouseX, this.mouseY)));
        }
        
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            if (!this.parent)
            {
            	return;
            }
            
            currentCol = (DrawingPage(this.parent).allLocked) ? rhLockedColor : rhColor;

            super.updateDisplayList(unscaledWidth,unscaledHeight);
            
            if (graphics)
            {
                graphics.clear();
                graphics.beginFill(0, 0);
                graphics.lineStyle(outlineThickness, outlineColor, outlineAlpha);
                graphics.drawRect(0, 0, this.width, this.height);
                graphics.endFill();
                updateSelectionMarkers();
            };
        }

        public static function clone(mani:Manipulator):Manipulator
        {
            return (new Manipulator(mani.TLC.x, mani.TLC.y, mani.width, mani.height, mani.angle));
        }

    }
}